using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Globalization;
using Caliburn.Micro;
using MediaOwl.Common;
using MediaOwl.Common.Messages;
using MediaOwl.Common.ScreenManagement;
using MediaOwl.LastFm.Data;
using MediaOwl.LastFm.Model;
using MediaOwl.LastFm.Resources;

namespace MediaOwl.LastFm.ViewModels
{
    [Export(typeof(IWorkitem<LastFmViewModel>))]
    public sealed class MusicArtistHomeViewModel : Workitem<LastFmViewModel>
    {
        #region Fields
        private readonly ILastFmDataRepository repository;
        private readonly IEventAggregator eventAggregator;

        #endregion

        #region Constructor
        [ImportingConstructor]
        public MusicArtistHomeViewModel(ILastFmDataRepository repository, IEventAggregator eventAggregator)
        {
            DisplayName = Captions.MusicArtistHomeTitle;
            this.repository = repository;
            this.eventAggregator = eventAggregator;
            IsHomeScreen = true;
            Order = 0;
            Artists = new BindableCollection<Artist>();

            int ipp;
            itemsPerPage = int.TryParse(LastFmDataAccess.DefaultPageSize, NumberStyles.Integer, CultureInfo.CurrentUICulture, out ipp)
                ? ipp
                : 20;
        }

        #endregion

        #region Properties & Backingfields

        private BindableCollection<Artist> artists;
        public BindableCollection<Artist> Artists
        {
            get { return artists; }
            set { artists = value; NotifyOfPropertyChange(() => Artists);}
        }

        private Artist selectedItem;
        public Artist SelectedItem
        {
            get { return selectedItem; }
            set
            {
                selectedItem = value;
                NotifyOfPropertyChange(() => SelectedItem);
            }
        }

        private Search currentSearch;
        public Search CurrentSearch
        {
            get { return currentSearch; }
            set
            {
                currentSearch = value;

                if (!Equals(ItemsPerPage, currentSearch.ItemsPerPage))
                    ItemsPerPage = currentSearch.ItemsPerPage;

                if (!Equals(CurrentPage, currentSearch.StartPage))
                    CurrentPage = currentSearch.StartPage;

                NotifyOfPropertyChange(() => CurrentSearch);
                NotifyOfPropertyChange(() => SearchResultText);
                NotifyOfPropertyChange(() => TotalResults);
                NotifyOfPropertyChange(() => CanNext);
                NotifyOfPropertyChange(() => CanPrevious);
            }
        }

        private string searchText;
        public string SearchText
        {
            get { return searchText; }
            set
            {
                searchText = value;
                NotifyOfPropertyChange(() => SearchText);
                NotifyOfPropertyChange(() => CanSearchItems);
            }
        }

        public bool CanSearchItems
        {
            get
            {
                if (string.IsNullOrEmpty(SearchText))
                {
                    return false;
                }
                return true;
            }
        }

        public bool CanNext
        {
            get
            {
                return CurrentPage * ItemsPerPage < TotalResults;
            }
        }

        public bool CanPrevious
        {
            get
            {
                return CurrentPage > 1;
            }
        }

        public long TotalResults
        {
            get
            {
                return CurrentSearch == null ? 0 : CurrentSearch.TotalResults;
            }
        }

        private int itemsPerPage;
        public int ItemsPerPage
        {
            get
            {
                return itemsPerPage;
            }
            set
            {
                if (itemsPerPage == value)
                    return;
                itemsPerPage = value;
                NotifyOfPropertyChange(() => ItemsPerPage);
            }
        }

        private int currentPage;
        public int CurrentPage
        {
            get { return currentPage; }
            set
            {
                if (value == currentPage)
                    return;
                currentPage = value;
                NotifyOfPropertyChange(() => CurrentPage);
            }
        }

        public string SearchResultText
        {
            get
            {
                return CurrentSearch == null 
                    ? string.Empty 
                    : CurrentSearch.SearchResultText;
            }
        }

        #endregion

        #region Methods

        public IEnumerator<IResult> SearchItems()
        {
            return Search();
        }

        public IEnumerator<IResult> SearchShortCut()
        {
            return IsActive && CanSearchItems ? Search() : null;
        }

        private IEnumerator<IResult> Search()
        {
            yield return Show.Busy(this);

            yield return repository.GetArtists(SearchText, (items, search) =>
                                                               {
                                                                   Artists.Clear();
                                                                   Artists.AddRange(items);
                                                                   CurrentSearch = search;
                                                               }, x => eventAggregator.Publish(new ErrorMessage(x)), CurrentPage);
            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> Next()
        {
            CurrentPage++;
            return Search();
        }

        public IEnumerator<IResult> Previous()
        {
            CurrentPage--;
            return Search();
        }

        public IEnumerator<IResult> Open()
        {
            if (SelectedItem == null)
            {
                yield break;
            }
            yield return Show.Child<MusicArtistSingleViewModel>(Helper.GetScreenId(SelectedItem))
                .In(Parent)
                .Configured(a =>
                                {
                                    a.WithArtist(SelectedItem);
                                    SelectedItem = null;
                                });          
        }

        #endregion
    }
}